package com.jike.refletct;

import java.lang.reflect.Method;

public class ExtMethod {

    public static void main(String[] args) throws Exception {
        refletctV4();
    }

    public static void ref(int i) {
    }

    public static void refletctV4() throws Exception {
        Class klass = Class.forName("com.jike.refletct.ExtMethod");
        Method method = klass.getMethod("ref", int.class);
        Object[] arg = new Object[1]; // 在循环外构造参数数组
        // 缓存字节码文件中的Integer装箱操作
        // invokestatic Integer.valueOf
        arg[0] = 128;
        long current = System.currentTimeMillis();
        for (int i = 1; i <= 2_000_000_000; i++) {
            if (i % 100_000_000 == 0) {
                long temp = System.currentTimeMillis();
                System.out.println(temp - current);
                current = temp;
            }
            method.invoke(null, arg);
        }
    }

    public static void reflectV3() throws Exception {
        Class klass = Class.forName("com.jike.refletct.ExtMethod");
        Method method = klass.getMethod("ref", int.class);
        long current = System.currentTimeMillis();
        for (int i = 1; i <= 2_000_000_000; i++) {
            if (i % 100_000_000 == 0) {
                long temp = System.currentTimeMillis();
                System.out.println(temp - current);
                current = temp;
            }
            method.invoke(null, 128);
        }
    }

    /**
     * 调用次数小于15次的时候
     * at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     * at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
     * at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
     * 当调用15次以上的时候（该方式直接从本地调用转换为invoke指令字节调用字节码的方式）
     * 该方式绕过了反射调用从java ->C++ ->java的三层路径，性能通常是本地调用的20倍以上
     * 其中GeneratedMethodAccessor1是java虚拟机额外加装的类
     * at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
     * at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
     */
    public static void refletctV2() throws Exception {
        for (int i = 1; i <= 20; i++) {
            Class<?> klass = Class.forName("com.jike.refletct.ExtMethod");
            Method method = klass.getMethod("target", int.class);
            method.invoke(null, 1);
        }
    }

    public static void refletctV1() throws Exception {
        Class<?> klass = Class.forName("com.jike.refletct.ExtMethod");
        Method method = klass.getMethod("target", int.class);
        method.invoke(null, 1);
    }

    /*
    java.lang.Exception: #1
        at com.jike.ExtMethod.target(ExtMethod.java:16)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at com.jike.ExtMethod.main(ExtMethod.java:11)
	可以看到，反射调用先是调用了 Method.invoke，然后进入委派实现（DelegatingMethodAccessorImpl），再然后进入本地实现（NativeMethodAccessorImpl），最后到达目标方法。
    * */
    public static void target(int i) {
        System.out.println(i);
        new Exception("#" + i).printStackTrace();
    }
}
